﻿using AutoMapper;
using FireBillBook.Core.Dtos;
using FireBillBook.Core.Entities;
using FireBillBook.Core.Models;
using FireBillBook.Core.Models.QueryContexts;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace FireBillBook.Core.Repos
{
    public class ConsumptionRecordRepo : IConsumptionRecordRepo
    {
        private BillDbContext _db;
        private IServiceProvider _provider;

        public ConsumptionRecordRepo(BillDbContext dbContext, IServiceProvider serviceProvider)
        {
            _db = dbContext;
            _provider = serviceProvider;
        }

        public async Task DeleteAsync(int id)
        {
            var oldRecord = await _db.ConsumptionRecords.AsQueryable().FirstOrDefaultAsync(a => a.Id.Equals(id));
            if (oldRecord == null) { return; }

            oldRecord.IsDeleted = true;
            oldRecord.DeletedTime = DateTime.Now;

            await _db.SaveChangesAsync();

        }

        public async Task<ConsumptionRecord> GetByIdAsync(int id, bool excludeDeleted)
        {
            var query = _db.ConsumptionRecords.AsNoTracking();

            if(excludeDeleted)
            {
                query = query.Where(a => a.IsDeleted == false);
            }
            return await query.FirstOrDefaultAsync(a => a.Id.Equals(id));
        }

        public async Task<PagingModel<ConsumptionRecordDto>> ListAsyc(ConsumptionRecordListQueryContext queryContext, bool excludeDeleted)
        {
            var query = _db.ConsumptionRecords.AsNoTracking();

            if(excludeDeleted)
            {
                query = query.Where(a => a.IsDeleted == false);
            }

            if (!string.IsNullOrEmpty(queryContext.Keyword))
            {
                query = query.Where(a => a.Description.Contains(queryContext.Keyword));
            }

            if(queryContext.Start != null)
            {
                query = query.Where(a => a.TradingTime.Date.CompareTo(queryContext.Start.Value.Date) >= 0);
            }

            if(queryContext.End != null)
            {
                query = query.Where(a => a.TradingTime.Date.CompareTo(queryContext.End.Value.Date) <= 0);
            }

            var paging = queryContext.ConvertToPagingModel<ConsumptionRecordDto>();

            paging.Total = await query.CountAsync();
            query = queryContext.TryPaging(query);

            var resultQuery = from record in query
                              join type in _db.ConsumptionTypes on record.ConsumptionTypeId equals type.Id into groupTypes
                              from gt in groupTypes.DefaultIfEmpty()
                              join platform in _db.TradingPlatforms on record.TradingPlatform equals platform.Name into groupPlatforms
                              from gp in groupPlatforms.DefaultIfEmpty()
                              join account in _db.TradingAccounts on record.TradingAccountId equals account.Id into groupAccounts
                              from ga in groupAccounts.DefaultIfEmpty()
                              select new ConsumptionRecordDto
                              {
                                  Id = record.Id,
                                  Description = record.Description,
                                  FlowDirection = record.FlowDirection,
                                  Amount = record.Amount,
                                  TradingAccountId = record.TradingAccountId,
                                  TradingAccountName = ga.Name,
                                  ConsumptionTypeId = record.ConsumptionTypeId,
                                  ConsumptionTypeName = gt.Name,
                                  TradingPlatform = record.TradingPlatform,
                                  TradingPlatformName = gp.Name,
                                  TradingTime = record.TradingTime
                              };

            paging.Collection = await resultQuery.ToListAsync();

            return paging;
        }

        public async Task SaveAsync(ConsumptionRecordDto record)
        {
            if(record.Id == 0)
            {
                var mapper = _provider.GetRequiredService<IMapper>();
                // new
                var model = mapper.Map<ConsumptionRecord>(record);
                model.CreatedTime = DateTime.Now;

                _db.ConsumptionRecords.Add(model);
                await _db.SaveChangesAsync();
            }
            else
            {
                // update
                var oldRecord = await _db.ConsumptionRecords.AsQueryable().FirstOrDefaultAsync(a => a.Id.Equals(record.Id));
                if (oldRecord == null) throw new FireBillingBookException(-1, "未找到要更新的记录");

                oldRecord.Description = record.Description;
                oldRecord.Amount = record.Amount;
                oldRecord.UpdatedTime = DateTime.Now;

                await _db.SaveChangesAsync();
            }
        }
    }
}
